package handler;

import Factory.ListenerFactory;
import Factory.RequestFactory;
import Factory.request.RequestParams;
import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import io.netty.util.HashedWheelTimer;
import sys.Console;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TcpHandler extends SimpleChannelInboundHandler<ByteBuf> {

    private static Console console = Console.getInstance();

    private static Map<String, ChannelHandlerContext> contextMap = new HashMap<>();

    private ByteBuf buf = Unpooled.buffer();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.channel().config().setWriteBufferHighWaterMark(1024 * 1024 * 8);
        System.out.println("the netty client has been started");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf tempBuf = (ByteBuf) msg;
        if (tempBuf.toString(CharsetUtil.UTF_8).equals("heartbeat")) {
            return;
        }
        buf.writeBytes(tempBuf);
        String[] split = buf.toString(CharsetUtil.UTF_8).split("\\{");
        int dataLength = Integer.parseInt(split[0]);
        console.info("接收到的数据长度:" + (buf.readableBytes() - split[0].length()));
        if (buf.readableBytes() - split[0].length() >= dataLength) {
            Map<String, Object> map = new HashMap<>();
            try{
                console.info(buf.toString(CharsetUtil.UTF_8).substring(split[0].length()));
                map = JSONObject.parseObject(buf.toString(CharsetUtil.UTF_8).substring(split[0].length()));
            } catch (Exception e) {
                e.printStackTrace();
                console.sexy("-------------------------------------------------------");
            }
            FullHttpRequest fullHttpRequest = MapToFullHttoRequest(map);
            final Object o = HttpHandler.sendMessage(fullHttpRequest);
            Map<String, Object> resMap = getResMap((FullHttpResponse) o);
            String s = JSONObject.toJSON(resMap).toString();
            String ret = s.length() + s;
            buf = Unpooled.buffer();
            ctx.writeAndFlush(Unpooled.copiedBuffer(ret, CharsetUtil.UTF_8)).addListener(ListenerFactory.getDefaultListener("------sucess to server------"));
        }
    }

    @Override
    protected void messageReceived(ChannelHandlerContext channelHandlerContext, ByteBuf in) throws Exception {

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }

    /**
     * 如果2分钟没有读请求，则向客户端发送心跳
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (IdleState.READER_IDLE.equals((event.state()))) {
                console.info("send a hearbeat");
                ctx.writeAndFlush(Unpooled.copiedBuffer("heartbeat", CharsetUtil.UTF_8)).addListener(ListenerFactory.getDefaultListener("successfully send heartbeat")) ;
            }
        }
        super.userEventTriggered(ctx, evt);
    }

    private FullHttpRequest MapToFullHttoRequest(Map<String, Object> map) throws URISyntaxException {
        FullHttpRequest fullHttpRequest = getRequest(map);
        return fullHttpRequest;
    };

    /**
     * 解析请求返回的参数
     * @param response
     * @return
     */
    private Map<String, Object> getResMap(FullHttpResponse response) {
        System.out.println(response);
        Map<String, Object> map = new HashMap<>();
        List<Map.Entry<CharSequence, CharSequence>> entries = response.headers().entries();
        for (Map.Entry<CharSequence, CharSequence> entry : entries) {
            map.put(entry.getKey().toString(), entry.getValue());
        };
        ByteBuf buf = response.content();
        String result = buf.toString(CharsetUtil.UTF_8);
        map.put("result", result);
        map.put("status", response.status());
        return map;
    }

    /**
     * 获取FullHttpRequest
     * @param map
     * @return
     * @throws URISyntaxException
     */
    private FullHttpRequest getRequest(Map<String, Object> map) throws URISyntaxException {
        RequestParams requestParams = null;
        FullHttpRequest fullHttpRequest = null;
        if (map.get("method").toString().equals("GET")) {
            requestParams = new RequestParams(HttpVersion.HTTP_1_1, HttpMethod.GET, new URI(map.get("uri").toString()));
            requestParams.setHeaders(map);
            fullHttpRequest = RequestFactory.getGetFullRequest(requestParams);
        }
        if (map.get("method").toString().equals("POST")) {
            requestParams = new RequestParams(HttpVersion.HTTP_1_1, HttpMethod.POST, new URI(map.get("uri").toString()));
            requestParams.setParams(map.get("params").toString())
                    .setHeaders(map);
            fullHttpRequest = RequestFactory.getPostFullRequest(requestParams);
        }
        return fullHttpRequest;
    }
}

